package com.ftf.tp.blog.application.service.command.impl;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ftf.tp.blog.application.adapter.http.UserHttpAdapter;
import com.ftf.tp.blog.application.adapter.producer.DomainEventPublisher;
import com.ftf.tp.blog.application.adapter.producer.NeedSaveEventResult;
import com.ftf.tp.blog.application.dto.command.PublishArticleCommand;
import com.ftf.tp.blog.application.dto.message.SupportMessage;
import com.ftf.tp.blog.application.service.command.ArticleCommandService;
import com.ftf.tp.blog.domain.article.aggregate.ArticleAgg;
import com.ftf.tp.blog.domain.article.dos.SupportDO;
import com.ftf.tp.blog.domain.article.event.PublishArticleEvent;
import com.ftf.tp.blog.domain.article.repository.ArticleRepository;
import com.ftf.tp.blog.domain.article.service.ArticleService;
import com.ftf.tp.common.constants.RedisConstant;
import com.ftf.tp.common.core.redis.utils.RedissonHelper;
import com.ftf.tp.common.core.utils.IPUtils;
import com.ftf.tp.common.cqrs.annotation.ApplicationService;
import com.ftf.tp.common.cqrs.annotation.CommandHandler;
import com.ftf.tp.user.client.dto.UserInfoDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.Instant;


/**
 * 文章应用服务实现类
 *
 * @author tanghao
 * @date 2022/6/24
 */
@Slf4j
@Service
@ApplicationService
public class ArticleCommandServiceImpl implements ArticleCommandService {
    @Resource
    private ArticleService articleService;

    @Resource
    private RocketMQTemplate rocketMqTemplate;

    @Resource
    private ArticleRepository articleRepository;

    @Resource
    private RedissonHelper redissonHelper;

    @Resource
    private DomainEventPublisher domainEventPublisher;

    @Autowired
    private UserHttpAdapter userAdapter;

    /**
     * 发布文章
     *
     * @param publishArticleCommand 文章发布命令
     */
    @Override
    @CommandHandler
    @Transactional(rollbackFor = Exception.class)
    public void publishArticle(PublishArticleCommand publishArticleCommand) {
//        try {
//            //文章审核--要保证消息的不丢失
//            rocketMqTemplate.syncSend(RocketMqConstant.REVIEW_BLOG_TAG, articlePublishAo);
//        } catch (Exception e) {
//            log.error("文章审核消息发送失败 :{}", JSON.toJSONString(articlePublishAo), e);
//            //todo 文章打回草稿状态。
//             发送用户消息
//        }
        //转换聚合根
        UserInfoDTO currentUser = userAdapter.getCurrentUser();
        ArticleAgg articleAgg = publishArticleCommand.doForward(currentUser);
        //文章初始保存
        articleService.initialSave(articleAgg);
        //发布领域事件
        domainEventPublisher.publishBySpring(new PublishArticleEvent(articleAgg));

        //todo 通知关注用户
    }

    /**
     * 浏览blog
     *
     * @param userId             用户id 游客为空
     * @param articleId          文章id
     * @param httpServletRequest 请求
     */
    @Override
    public void browseArticle(Long userId, Long articleId, HttpServletRequest httpServletRequest) {
        //得到当前请求的ip
        String ip = IPUtils.getIpAddr(httpServletRequest);
        String browseKey = getBrowseKey(ip, articleId);
        String sumKey = RedisConstant.REDIS_KEY_ARTICLE_BROWSE_COUNT + ":" + articleId;
        //通过这个key控制5分钟内同ip访问同文章，只加一遍
        if (ObjectUtils.isEmpty(redissonHelper.getValue(browseKey))) {
            redissonHelper.setValueAndSeconds(browseKey, 0, 60 * 5);
            //浏览文章相关缓存操作
            //浏览数+1
            articleRepository.browseBlog(sumKey, articleId);
            //如果是登陆用户浏览，就保存浏览记录
            if (ObjectUtils.isNotEmpty(userId)) {
                String key = RedisConstant.MAP_KEY_USER_BROWSE_RECORD + ":" + userId;
                //访问时间
                double score = Instant.now().toEpochMilli();
                redissonHelper.addZset(key, articleId, score);
                log.info("用户 {} 访问文章 {},ip地址为{}", userId, articleId, ip);
            } else {
                log.info("游客 访问文章 {},ip地址为{}", articleId, ip);
            }
        }
    }


    /**
     * 拼接用户ip和文章id作为key。格式 222222::333333
     *
     * @param ip     用户ip
     * @param blogId 文章id
     */
    public static String getBrowseKey(String ip, Long blogId) {
        return ip + "::" + blogId;
    }

    /**
     * 文章点赞
     *
     * @param supportMessage 参数
     */
    @Override
    @NeedSaveEventResult
    public void articleSupport(SupportMessage supportMessage) {
        SupportDO supportDO = supportMessage.getData().toSupportDO();
        articleService.articleSupport(supportDO);
    }

    @Override
    public void climbBlog(String userName, Long userId, String authorName, Long bigTag) {
        articleRepository.climbBlog(userName, userId, authorName, bigTag);
    }

    @Override
    public void createIndex() throws Exception {
        articleRepository.createIndex();
    }

    @Override
    public void get() {
        articleRepository.get();
    }
}
